# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1078.1.14 -> 1.1078.1.15 # kernel/time.c 1.11 -> 1.12 # kernel/timer.c 1.52 -> 1.53 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/14 davidm@tiger.hpl.hp.com 1.1078.1.15 # Change last_time_offset into last_nsec_offset and make it work for real. # -------------------------------------------- # diff -Nru a/kernel/time.c b/kernel/time.c --- a/kernel/time.c Thu May 15 13:41:55 2003 +++ b/kernel/time.c Thu May 15 13:41:55 2003 @@ -35,7 +35,7 @@ */ struct timezone sys_tz; -extern unsigned long last_time_offset; +extern unsigned long last_nsec_offset; #if !defined(__alpha__) && !defined(__ia64__) @@ -79,7 +79,7 @@ write_seqlock_irq(&xtime_lock); xtime.tv_sec = value; xtime.tv_nsec = 0; - last_time_offset = 0; + last_nsec_offset = 0; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; @@ -125,7 +125,7 @@ { write_seqlock_irq(&xtime_lock); xtime.tv_sec += sys_tz.tz_minuteswest * 60; - last_time_offset = 0; + last_nsec_offset = 0; write_sequnlock_irq(&xtime_lock); } @@ -381,7 +381,7 @@ txc->calcnt = pps_calcnt; txc->errcnt = pps_errcnt; txc->stbcnt = pps_stbcnt; - last_time_offset = 0; + last_nsec_offset = 0; write_sequnlock_irq(&xtime_lock); do_gettimeofday(&txc->time); return(result); diff -Nru a/kernel/timer.c b/kernel/timer.c --- a/kernel/timer.c Thu May 15 13:41:55 2003 +++ b/kernel/timer.c Thu May 15 13:41:55 2003 @@ -451,6 +451,7 @@ */ struct timespec xtime __attribute__ ((aligned (16))); struct timespec wall_to_monotonic __attribute__ ((aligned (16))); +unsigned long last_nsec_offset; /* Don't completely fail for HZ > 500. */ int tickadj = 500/HZ ? : 1; /* microsecs */ @@ -605,7 +606,7 @@ /* in the NTP reference this is called "hardclock()" */ static void update_wall_time_one_tick(void) { - long time_adjust_step; + long time_adjust_step, delta_nsec; if ( (time_adjust_step = time_adjust) != 0 ) { /* We are doing an adjtime thing. @@ -621,11 +622,11 @@ time_adjust_step = tickadj; else if (time_adjust < -tickadj) time_adjust_step = -tickadj; - + /* Reduce by this step the amount of time left */ time_adjust -= time_adjust_step; } - xtime.tv_nsec += tick_nsec + time_adjust_step * 1000; + delta_nsec = tick_nsec + time_adjust_step * 1000; /* * Advance the phase, once it gets to one microsecond, then * advance the tick more. @@ -634,13 +635,33 @@ if (time_phase <= -FINEUSEC) { long ltemp = -time_phase >> (SHIFT_SCALE - 10); time_phase += ltemp << (SHIFT_SCALE - 10); - xtime.tv_nsec -= ltemp; + delta_nsec -= ltemp; } else if (time_phase >= FINEUSEC) { long ltemp = time_phase >> (SHIFT_SCALE - 10); time_phase -= ltemp << (SHIFT_SCALE - 10); - xtime.tv_nsec += ltemp; + delta_nsec += ltemp; + } + xtime.tv_nsec += delta_nsec; + + /* + * The whole point of last_nsec_offset is that it can be updated atomically and + * lock-free. Thus, arches that don't have __HAVE_ARCH_CMPXCHG probably can't use + * last_nsec_offset anyhow... --davidm 2003-Feb-11 + */ +#ifdef __HAVE_ARCH_CMPXCHG + if (last_nsec_offset > 0) { + unsigned long new, old; + + do { + old = last_nsec_offset; + if (old > delta_nsec) + new = old - delta_nsec; + else + new = 0; + } while (cmpxchg(&last_nsec_offset, old, new) != old); } +#endif } /* @@ -777,7 +798,6 @@ #ifndef ARCH_HAVE_XTIME_LOCK seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; #endif -unsigned long last_time_offset; /* * This function runs timers and the timer-tq in bottom half context. @@ -811,7 +831,6 @@ wall_jiffies += ticks; update_wall_time(ticks); } - last_time_offset = 0; calc_load(ticks); }